//{-------------head----------------------------------
//
//! @file    G4.1.cpp
//! @brief   My epic calculator.
//!
//! @warning NEVER ENTER ^C symbol! JUST DON'T DO IT!!!@!1!
//
//}-------------head----------------------------------

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

#define _CRT_SECURE_NO_WARNINGS 1

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

// G4 ::= E
// E ::= T { [+-] T } *
// T ::= P { [*/] P } *
// P ::= - ( E ) | - N | ( E ) | N
// N ::= [0-9] +

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

//{-------------calc----------------------------------
//! @brief   Exceptions:
//!			 - EXC_OK:    it's ok;
//!			 - EXC_NUM:   num reading exc;
//!			 - EXC_DIV_0: division by 0;
//!			 - EXC_BKT:   wrong bracket sequence;
//!
//! @warning NEVER ENTER ^C symbol! JUST DON'T DO IT!!!@!1!
//}-------------calc----------------------------------

typedef enum Exc Exc;

enum Exc {
	EXC_OK    = 0,
	EXC_NUM   = 1,
	EXC_DIV_0 = 2,
	EXC_BKT   = 3,
};

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

//{-------------calc----------------------------------
//! @brief   Cursor. It's global in order to fasten program.
//!
//! @warning NEVER ENTER ^C symbol! JUST DON'T DO IT!!!@!1!
//}-------------calc----------------------------------

const char *S = NULL;

//{-------------calc----------------------------------
//! @brief   Flag of exception is got or not.
//!
//! @warning NEVER ENTER ^C symbol! JUST DON'T DO IT!!!@!1!
//}-------------calc----------------------------------

Exc flag = EXC_OK;

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

//{-------------calc----------------------------------
//! @brief   Main recursive func. Like a head of 'em all. 
//!
//! @warning NEVER ENTER ^C symbol! JUST DON'T DO IT!!!@!1!
//}-------------calc----------------------------------

int GetG4 (const char *str);

//{-------------calc----------------------------------
//! @brief   Gets a number from input.
//!
//! @warning NEVER ENTER ^C symbol! JUST DON'T DO IT!!!@!1!
//}-------------calc----------------------------------

int GetN ();

//{-------------calc----------------------------------
//! @brief   Gets an expression from input (is made from T).
//!
//! @warning NEVER ENTER ^C symbol! JUST DON'T DO IT!!!@!1!
//}-------------calc----------------------------------

int GetE ();

//{-------------calc----------------------------------
//! @brief   Gets a token from input (is made from P).
//!
//! @warning NEVER ENTER ^C symbol! JUST DON'T DO IT!!!@!1!
//}-------------calc----------------------------------

int GetT ();

//{-------------calc----------------------------------
//! @brief   Gets an in-brackets or a number. ((E) or N).
//!
//! @warning NEVER ENTER ^C symbol! JUST DON'T DO IT!!!@!1!
//}-------------calc----------------------------------

int GetP ();

//{-------------calc----------------------------------
//! @brief   Skips all spaces.
//!
//! @warning NEVER ENTER ^C symbol! JUST DON'T DO IT!!!@!1!
//}-------------calc----------------------------------

void space_killer ();

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

int main (int argc, const char *argv[])
{
	printf ("# Hello @! This is %s. \n# It's compiled %s at %s by Anton Samsonov\n\n",
			strrchr (argv[0], '\\' ) + 1, __DATE__, __TIME__);
	printf ("Enter an expression to calculate. You can use __+-*/()__ symbols.\n"
			"Program is using integers, so you can't get abs(number) > pow(2, 31) +- 1.\n");

	char str[200] = {};
	int ok = scanf_s ("%[^\n]", str, 200); // warning: never! enter ^C symbol. just don't do it.
	if (!ok) {
		printf ("Input is bad. Can't calculate things kinda that.\n");
		return 0;
	}
	GetG4 (str);
	return 0;
}

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

int GetG4 (const char *str)
{
	S = str;
	int val = GetE ();
	if (!(*S == '\0') || flag != EXC_OK) {
		printf ("Expression: __%s__ is not valid: ", str);
		switch (flag) {
			case EXC_OK    : printf ("%c symbol got.", *S);      break;
			case EXC_NUM   : printf ("%c symbol got.", *S);      break;
			case EXC_DIV_0 : printf ("division by 0.");          break;
			case EXC_BKT   : printf ("wrong bracket sequence."); break;
			default : printf ("undefined exception got.");
		}
		printf ("\n");
		return 0;
	}
	printf ("Expression: __%s__ is ok. Result is equal to __%d__.\n", str, val);
	return val;
}

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

int GetN ()
{
	int val = 0;
	if (!('0' <= *S && *S <= '9')) {
		flag = EXC_NUM;
		return -1;
	}
	while ('0' <= *S && *S <= '9') {
		val = val * 10 + *S - '0';
		S++;
	}

	return val;
}

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

int GetE ()
{
	int val = GetT ();
	if (flag != EXC_OK) 
		return -1;
	while (*S == '+' || *S == '-') {
		char op = *S;
		S++;

		int val2 = GetT ();
		if (flag != EXC_OK) 
			return -1;

		if (0);
		else if (op == '+') 
			val += val2;
		else if (op == '-')
			val -= val2;
	}
	return val;
}

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

int GetT ()
{
	int val = GetP ();
	if (flag != EXC_OK) 
		return -1;
	while (*S == '*' || *S == '/') {
		char op = *S;
		S++;

		int val2 = GetP ();
		if (flag != EXC_OK) 
			return -1;

		if (0);
		else if (op == '*') 
			val *= val2;
		else if (op == '/')
			if (val2 != 0)
				val /= val2;
			else {
				flag = EXC_DIV_0;
				return -1;
			}
	}
	return val;
}

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

int GetP ()
{
	space_killer ();
	
	int sign = 1;
	if (*S == '-') {
		sign = -1;
		*S++;
	}

	if (*S == '(') {
		S++;
		int val = GetE ();
		if (flag != EXC_OK) 
			return -1;

		if (*S != ')') {
			flag = EXC_BKT;
			return -1;
		}
		S++;

		space_killer ();
		return val * sign;
	}
	else {
		space_killer ();

		int val = GetN ();
		if (flag != EXC_OK) 
			return -1;

		space_killer ();
		return val * sign;
	}
}

// -------------------------------------------------------------------------------------------------------------------------
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
// -------------------------------------------------------------------------------------------------------------------------

void space_killer ()
{
	while (*S == ' ')
		S++;
}